package com.gitee.yusugar.core.ssh;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.ssh.ChannelType;
import cn.hutool.extra.ssh.JschUtil;
import com.jcraft.jsch.Channel;
import lombok.extern.slf4j.Slf4j;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.Scanner;

/**
 * @author Y.sugar
 * @date 2023/1/9 15:32
 */
@Slf4j
public class TerminalSSH {

    private Channel channel = null;
    private OutputStream os = null;
    private InputStream in = null;

    /**
     * 创建通道
     * @param sshInfo session对象
     * @return 是否创建成功
     */
    public boolean createChannel(SSHInfo sshInfo) {
        try {
            // 开启session
            boolean openState = sshInfo.openSession();
            if (!openState) {
                return false;
            }
            // 创建通道并建立连接
            channel = JschUtil.createChannel(sshInfo.getSession(), ChannelType.SHELL);
            channel.connect();

            // 获取通道的输入输出流
            os = channel.getOutputStream();
            in = channel.getInputStream();
            return true;
        } catch (Exception e) {
            log.error("通道创建失败");
            return false;
        }
    }

    /**
     * 关闭通道和流
     */
    public void close() {
        IoUtil.close(os);
        IoUtil.close(in);
        JschUtil.close(channel);
    }

    /**
     * 判断通道连接是否关闭
     * @return true关闭 false未关闭
     */
    public boolean channelClosed(){
        return !channel.isConnected();
    }

    /**
     * 读取设备返回数据（该种方法会返回用户输入的数据）
     * @return 设备返回数据
     */
    public String read() {
        return read(null);
    }

    /**
     * 读取设备返回数据
     * @param userInputStr 用户输入的字符
     * @return 设备返回数据
     */
    public String read(String userInputStr) {
        try {
            // 获取输入流并返回结果
            /*int startByte = in.read();
            int length = in.available();
            byte[] byteData = new byte[length + 1];
            byteData[0] = (byte) startByte;
            in.read(byteData, 1, length);*/
            int length = in.available();
            while (length == 0) {
                length = in.available();
            }
            byte[] byteData = new byte[length];
            in.read(byteData, 0, length);
            String dataStr = StrUtil.str(byteData, CharsetUtil.CHARSET_UTF_8);
            if (StrUtil.isNotBlank(userInputStr)) {
                dataStr = dataStr.replace(userInputStr, "").trim();
            }

            /* 第二种方法
            int length = in.available();
            while (length == 0) {
                length = in.available();
            }
            byte[] byteData = new byte[length];
            in.read(byteData, 0, length);*/

            return dataStr;
        } catch (Exception e) {
            log.error("读取通道数据失败");
            return null;
        }
    }

    /**
     * 往设备里写数据
     * @param userInputStr 用户输入的待入写数据
     */
    public void write(String userInputStr) {
        IoUtil.write(os, false, strConvertByte(userInputStr));
        IoUtil.flush(os);
    }

    /**
     * 往设备里写数据并读取返回结果
     * @param userInputStr 用户输入的待入写数据
     * @return 设备返回的执行结果
     */
    public String writeAndRead(String userInputStr) {
        write(userInputStr);
        return read(userInputStr);
    }

    /**
     * 转换用户输入的字符传为字节数组
     * @param str 用户输入的字符串
     * @return 字节数组
     */
    private static byte[] strConvertByte(String str) {
        return (str + "\n").getBytes(CharsetUtil.CHARSET_UTF_8);
    }

    public static void main(String[] args) throws Exception {
        //SSHInfo ssh = SSHUtil.createSSH("192.168.10.236", "admin", "admin");
        SSHInfo ssh = SSHUtil.createSSH("125.46.83.210", "root", "Zygh@)@@");

        TerminalSSH terminal = new TerminalSSH();
        terminal.createChannel(ssh);

        Scanner scanner = new Scanner(System.in);
        String userInputCmdStr = null;

        while (true) {
            if (StrUtil.isBlank(userInputCmdStr)){
                System.out.print(terminal.read());
            }

            userInputCmdStr = scanner.nextLine();
            terminal.write(userInputCmdStr);
            String execRes = terminal.read();
            //String execRes = terminal.writeAndRead(userInputCmdStr);
            System.out.print(execRes);
            if (terminal.channelClosed()){
                break;
            }

        }
        System.out.println("结束了");
        terminal.close();
    }

}
